import { buildingData, userData } from '../views/Home/data.json';
import { cloneDeep, groupBy, uniqBy } from 'lodash-es';
// import axios from 'axios';
// import AMapLoader from '@amap/amap-jsapi-loader';
import { getLocationByName } from './utils';
import { ElMessage } from 'element-plus';
import KDBush from 'kdbush';
import { around } from '@/utils/index';
// let amap: any = null;
// export const getAMap = async () => {
//   if (amap) return amap;
//   amap = await AMapLoader.load({
//     key: '15f4009727bea4db408319bc716a795d',
//     version: '2.0',
//     plugins: ['AMap.Geocoder', 'AMap.PlaceSearch'] // 加载地理编码插件
//   });
//   return amap;
// };

export type BuildingDataType = (typeof buildingData)[0] & {
  originalId?: string;
  uuid?: string;
  buildingNumber?: string;
  roomNumber?: string;
  floorNumber?: string;
  community?: string;
  position?: {
    latitude: number;
    longitude: number;
  };
};
export type UserDataType = (typeof userData)[0] & { uuid?: string };

type lastResultType = {
  buildIndex: number; //建筑索引
  userIndex: number; //用户索引
  score: number; //分数
  details: {
    userdata: UserDataType;
    buildData: BuildingDataType;
    totalScoreItem: {
      exactMatchScore: number;
      buildingRoomMatchScore: number;
      fuzzyTextMatchScore: number;
      spatialProximityMatchScore: number;
    };
  };
};

interface FusionDataParams {
  buildingData: BuildingDataType[];
  userData: UserDataType[];
}
export class FusionData {
  buildingDataOrigin: BuildingDataType[];
  userDataOrigin: UserDataType[];
  cacheHistory = new Map();
  mergeData: any[] = [];
  config = {
    exactMatchWeight: 0.3, // 降低精确匹配权重
    spatialWeight: 0.2, // 建筑+房号匹配权重
    semanticWeight: 0.3, // 语义匹配权重
    distanceWeight: 0.2, // 距离匹配权重
    threshold: 0.6, // 贪心算法 匹配阈值
    spatialDistanceThreshold: 100 // 空间距离阈值(米)
  };
  //分组
  userDataGroupBy: any = {};
  // 去重后用户数据
  uniqByUserList: UserDataType[] = [];

  //最后的结果
  lastResult: lastResultType[] = [];
  constructor({ buildingData, userData }: FusionDataParams) {
    this.buildingDataOrigin = buildingData;
    this.userDataOrigin = userData;
  }

  async handleDataCleaning() {
    // 用户数据分组
    this.handleUserDataGroupBy();
    // 去重用户数据
    this.handleUniqByUser();
    // 根据高德地图获取坐标
    const newList = await this.handleUseDataLocation();
    // console.log('获取坐标完成', newList);
    this.uniqByUserList = newList;
  }

  handleUserDataGroupBy() {
    const groupList = groupBy(this.userDataOrigin, 'fullRoomId');
    // console.log(groupList, '用户数据分组');
    this.userDataGroupBy = groupList;
  }
  handleUniqByUser() {
    const list = uniqBy(this.userDataOrigin, 'fullRoomId');
    this.uniqByUserList = list;
    // console.log(list, 'handleUniqByUser');
  }

  async handleUseDataLocation(): Promise<any[]> {
    const cacheHistory = new Map();
    const list = cloneDeep(this.uniqByUserList).map(item => {
      const keywords = item.community + item.buildingNumber?.replace(/\D/g, '') + '幢';
      return {
        ...item,
        keywords
      };
    });

    return new Promise(resolve => {
      const fn = async (i: number) => {
        if (i > list.length - 1) {
          resolve(list);
          return;
        }
        const keywords = list[i].keywords;
        if (cacheHistory.has(keywords)) {
          list[i].coordinates = cacheHistory.get(keywords);
          fn(i + 1);
        } else {
          const coordinates = await getLocationByName(keywords);
          // console.log(keywords, coordinates);
          if (coordinates) {
            list[i].coordinates = coordinates;
          }
          cacheHistory.set(keywords, coordinates);
          setTimeout(() => {
            fn(i + 1);
          }, 500);
        }
      };
      fn(0);
    });
  }

  // 数据融合
  runFusionData() {
    this.mergeData = this.buildingDataOrigin.map(build => {
      //统计分数
      const step1 = this.uniqByUserList.map(user => {
        const totalScoreItem = {
          // 精确匹配
          exactMatchScore: this.exactMatch(build, user),
          // 建筑+房号匹配
          buildingRoomMatchScore: this.buildingRoomMatch(build, user),
          // 语义匹配
          fuzzyTextMatchScore: this.fuzzyTextMatch(build, user),
          // 距离计算
          spatialProximityMatchScore: this.spatialProximityMatch(build, user, 500)
        };
        const score =
          totalScoreItem.exactMatchScore * this.config.exactMatchWeight +
          totalScoreItem.buildingRoomMatchScore * this.config.spatialWeight +
          totalScoreItem.fuzzyTextMatchScore * this.config.semanticWeight +
          totalScoreItem.spatialProximityMatchScore * this.config.distanceWeight;
        return {
          userdata: user,
          buildData: build,
          totalScoreItem,
          score
        };
      });

      return step1;
    });

    //贪心算法找最优解
    const response = this.optimalMatching(this.mergeData);

    this.lastResult = response;
    this.unMatchUserData();
    return response;
  }

  unMatchUserData() {
    const unList = this.uniqByUserList.filter(item => {
      return !this.lastResult.some(resItem => resItem.details.userdata.id === item.id);
    });
    const aaa = unList.map(item => {
      return this.mergeData.slice(0, 10).map((it2: any) => {
        return it2.find(it3 => it3.userdata.id === item.id);
      });
      // const findItem =  this.mergeData.find(item2=>item2.userdata.id===item.id)
    });

    console.log(unList, '未匹配的', aaa);
    const selectList = this.uniqByUserList.filter(item => {
      return this.lastResult.some(resItem => resItem.details.userdata.id === item.id);
    });
    const bbb = selectList.map(item => {
      return this.mergeData.slice(0, 10).map((it2: any) => {
        return it2.find(it3 => it3.userdata.id === item.id);
      });
      // const findItem =  this.mergeData.find(item2=>item2.userdata.id===item.id)
    });

    console.log(selectList, '匹配的', bbb, '最终的结果>>>', this.lastResult);
  }

  /**
   * 精确匹配
   * @param spatial 空间数据
   * @param property 属性数据
   */
  exactMatch(spatial: BuildingDataType, property: UserDataType) {
    // console.log(`开始精确匹配: `, spatial, property);
    if (spatial.originalId === property.fullRoomId) {
      return 1.0;
    }
    return 0;
  }
  /**
   * 建筑+房号匹配
   */
  buildingRoomMatch(spatial: BuildingDataType, property: UserDataType) {
    let score = 0;

    // 建筑匹配 (40%)
    if (this.isBuildingMatch(spatial.buildingNumber, property.buildingNumber)) {
      score += 0.4;
    }

    // 房号匹配 (40%)
    if (this.isRoomMatch(spatial.roomNumber, property.roomNumber)) {
      score += 0.4;
    }

    // 楼层匹配 (20%)
    if (
      spatial.floorNumber &&
      property.floorNumber &&
      spatial.floorNumber.toString() === property.floorNumber.toString()
    ) {
      score += 0.2;
    }

    return score;
  }

  /**
   * 建筑号匹配判断
   */
  isBuildingMatch(building1, building2) {
    if (!building1 || !building2) return false;

    const normalized1 = this.normalizeBuildingNumber(building1);
    const normalized2 = this.normalizeBuildingNumber(building2);

    return normalized1 === normalized2;
  }

  /**
   * 房号匹配判断
   */
  isRoomMatch(room1, room2) {
    if (!room1 || !room2) return false;

    const normalized1 = this.normalizeRoomNumber(room1);
    const normalized2 = this.normalizeRoomNumber(room2);

    return normalized1 === normalized2;
  }

  /**
   * 标准化建筑号
   */
  normalizeBuildingNumber(building) {
    if (!building) return '';

    return building.toString().toUpperCase().replace(/[^\w]/g, ''); // 移除非字母数字字符
  }
  /**
   * 标准化房间号
   */
  normalizeRoomNumber(room) {
    if (!room) return '';

    return room.toString().replace(/[^\d]/g, ''); // 只保留数字
  }

  /**
   * 模糊文本匹配
   */
  fuzzyTextMatch(spatial: BuildingDataType, property: UserDataType) {
    /**
     * 生成搜索文本
     */
    function generateSearchText(data: BuildingDataType | UserDataType) {
      const parts: string[] = [];

      if (data.community) parts.push(data.community);
      if (data.buildingNumber) parts.push(data.buildingNumber);
      if (data.roomNumber) parts.push(data.roomNumber);

      return parts.join('-').toLowerCase();
    }
    const spatialText = generateSearchText(spatial);
    const propertyText = generateSearchText(property);
    /**
     * 计算文本相似度
     */
    function calculateTextSimilarity(text1: string, text2: string) {
      if (!text1 || !text2) return 0;

      // 简单的编辑距离算法
      const len1 = text1.length;
      const len2 = text2.length;
      const maxLen = Math.max(len1, len2);

      if (maxLen === 0) return 1;

      // 计算相同字符的比例
      let matches = 0;
      const minLen = Math.min(len1, len2);

      for (let i = 0; i < minLen; i++) {
        if (text1[i] === text2[i]) {
          matches++;
        }
      }

      return matches / maxLen;
    }

    return calculateTextSimilarity(spatialText, propertyText);
  }

  /**
   * 空间邻近匹配
   */
  spatialProximityMatch(spatial: BuildingDataType, property: UserDataType, dis = 0) {
    if (!spatial.position || !property.coordinates) {
      return 0;
    }

    /**
     * 计算地理距离 (Haversine公式)
     */
    function calculateDistance(pos1, pos2) {
      const R = 6371000; // 地球半径(米)
      const lat1 = (pos1.latitude * Math.PI) / 180;
      const lat2 = (pos2.latitude * Math.PI) / 180;
      const deltaLat = ((pos2.latitude - pos1.latitude) * Math.PI) / 180;
      const deltaLon = ((pos2.longitude - pos1.longitude) * Math.PI) / 180;

      const a =
        Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2) +
        Math.cos(lat1) * Math.cos(lat2) * Math.sin(deltaLon / 2) * Math.sin(deltaLon / 2);
      const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

      return R * c;
    }

    let distance = calculateDistance(spatial.position, property.coordinates);

    distance = Math.abs(distance - dis);

    if (distance < this.config.spatialDistanceThreshold) {
      const res = Math.max(0, 1 - distance / this.config.spatialDistanceThreshold);

      return res;
    }

    return 0;
  }

  /**
   * 最优匹配算法
   * 使用匈牙利算法或贪心算法找到最佳匹配方案
   */
  optimalMatching(scoreList: { totalScoreItem: any; score: number }[][]) {
    const matches: any[] = [];
    const usedSpatial = new Set();
    const usedProperty = new Set();

    const allPairs: any[] = [];

    // 贪心算法：按相似度从高到低匹配
    for (let i = 0; i < scoreList.length; i++) {
      for (let j = 0; j < scoreList[i].length; j++) {
        if (scoreList[i][j].score >= this.config.threshold) {
          allPairs.push({
            buildIndex: i,
            userIndex: j,
            score: scoreList[i][j].score,
            details: scoreList[i][j]
          });
        }
      }
    }

    // 按相似度排序
    allPairs.sort((a, b) => b.score - a.score);

    // 贪心匹配
    for (const pair of allPairs) {
      if (!usedSpatial.has(pair.buildIndex) && !usedProperty.has(pair.userIndex)) {
        matches.push(pair);
        usedSpatial.add(pair.buildIndex);
        usedProperty.add(pair.userIndex);
      }
    }

    return matches;
  }

  cesiumPointDistance(coordinates: any) {
    const getD = Math.ceil((coordinates.altitude - 4.2) / 3) + 1;
    const res = this.lastResult
      .filter(item => item.details.buildData.floorNumber === getD.toString())
      .map(item => {
        const distance = this.spatialProximityMatch(item.details.buildData, { coordinates } as any);
        return {
          distance,
          ...item
        };
      })
      .sort((a, b) => b.distance - a.distance)[0];

    const allUser = this.userDataGroupBy[res.details.userdata.fullRoomId];

    return { ...res, allUser };
  }

  downloadJSON() {
    const downJSon = this.lastResult.map(item => {
      const detailsUser = this.userDataGroupBy[item.details.userdata.fullRoomId];
      return { ...item, details: { ...item.details, userdata: detailsUser } };
    });

    // 将JSON数据转换为字符串
    const jsonString = JSON.stringify(downJSon, null, 2); // 使用2个空格进行格式化，方便阅读
    // 创建Blob对象
    const blob = new Blob([jsonString], { type: 'application/json' });
    // 创建URL
    const url = URL.createObjectURL(blob);

    // 创建<a>标签
    const a = document.createElement('a');
    a.href = url;
    a.download = 'data.json'; // 默认文件名

    // 触发下载
    document.body.appendChild(a);
    a.click();

    // 清理
    document.body.removeChild(a);
    URL.revokeObjectURL(url);
  }

  searchPosition(location: any) {
    const getD = Math.ceil((location.altitude - 4.2) / 3) + 1;
    const res = this.lastResult.filter(
      item => item.details.buildData.floorNumber === getD.toString()
    );
    const points = res.map(item => ({
      lon: item.details.buildData.lng,
      lat: item.details.buildData.lat
    }));
    const index = new KDBush(points.length);
    for (const { lon, lat } of points) index.add(lon, lat);
    index.finish();
    const selectPosition = around(index, location.longitude, location.latitude, 1).filter(
      item => item ?? false
    );
    const resp = res[selectPosition[0]];
    if (!resp) {
      ElMessage.error('位置选取有误，请重写操作');
      return;
    }
    const allUser = this.userDataGroupBy[resp.details.userdata.fullRoomId];
    return { ...resp, allUser };
  }
}
